home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1996 September / MACPOWER-1996-09.ISO.7z / MACPOWER-1996-09.ISO / 第2特集:プラグイン大集合 / PIC2 Save / pic2maclib.c < prev    next >
Text File  |  1995-01-16  |  26KB  |  1,178 lines

  1. /*
  2.  *    PIC2 ファイル操作部 by やなぎさわ
  3.  *
  4.  */
  5. #define Photoshop_PlugIn
  6.  
  7. #define _PIC2_
  8. #include "pic2.h"
  9. #include "p2PlugInUtilities.h"
  10.  
  11. /* ----- 変数の宣言 ----- */
  12.  
  13. static uchar saver[30+1];            /* セーバ名                            */
  14. static short depth;                    /* 色数ただしビットの深さで入れる    */
  15. static short x_aspect;                /* Xの比率                            */
  16. static short y_aspect;                /* Yの比率                            */
  17. static long x_max;                    /* Xの最大サイズ                    */
  18. static long y_max;                    /* Yの最大サイズ                    */
  19. static short n_palette = 0;            /* パレット数                        */
  20. static short palette_bits = 0;        /* パレットの有効ビット長            */
  21. static uchar palette_data[256][3];    /* パレットバッファ                    */
  22.  
  23. typedef union {
  24.         uchar    d_char[4];
  25.         long    d_long;
  26.         short    d_short;
  27.         LONG    d_LONG;
  28.         SHORT    d_SHORT;
  29. } any_t;
  30.  
  31.  
  32. /* ------ プログラム ----- */
  33.  
  34. /*
  35.  * 文字列を指定文字数だけコピーをする。もし元の文字列が短い場合は
  36.  * スペースでうめる。
  37.  */
  38. static void
  39. strcpy2(
  40.     uchar    *dst,            /* コピー先 */
  41.     uchar    *src,            /* コピー元 */
  42.     long    n_str            /* 文字数 */
  43.     )
  44. {
  45.     for ( ;;) {
  46.         uchar c = *src++;
  47.         
  48.         if ( c == '¥0') break;
  49.         if ( --n_str < 0) break;
  50.         *dst++ = c;
  51.     }
  52.     while ( --n_str >= 0) *dst++ = ' ';
  53. }
  54.  
  55. /*
  56.  * memsetの長さが16ビット超でもOK版
  57.  */
  58. void
  59. l_memset(
  60.     void _HUGE_ *mem,        /* セットされるメモリ */
  61.     uchar data,                /* データ */
  62.     long n                    /* 長さ(byte) */
  63.     )
  64. {
  65.     uchar *p = (uchar *)mem;
  66.  
  67.     while( --n >= 0) *p++ = data;
  68. }
  69.  
  70. /*
  71.  * メモリを確保する
  72.  *
  73.  */
  74. static void* mem_alloc(long size)
  75. {
  76.     void* p;
  77.  
  78.     p = (void*)NewPtrClear(size);
  79.  
  80.     if (p == NULL)
  81.     {
  82.         p2errno = MemError();
  83.         return NULL;
  84.     }
  85.     // memset( p, 0, size);
  86.     return p;
  87. }
  88.  
  89. #ifdef    BIG_ENDIAN
  90. #    define    conv_endian_short(x)
  91. #    define    conv_endian_long(x)
  92. #else 
  93. /*
  94.  * 'data'中のshortデータのバイトオーダーを入れ替える。
  95.  */
  96. static void
  97. conv_endian_short(
  98.     any_t *data            /* 入れ替え対象のデータ */
  99.     )
  100. {
  101.     uchar c;
  102.  
  103.     c = data->d_char[0];
  104.     data->d_char[0] = data->d_char[1];
  105.     data->d_char[1] = c;
  106. }
  107.  
  108. /*
  109.  * 'data'中のlongデータのバイトオーダーを入れ替える
  110.  */
  111. static void
  112. conv_endian_long(
  113.     any_t *data            /* 入れ替え対象のデータ */
  114.     )
  115. {
  116.     uchar c;
  117.     
  118.     c = data->d_char[0];
  119.     data->d_char[0] = data->d_char[3];
  120.     data->d_char[3] = c;
  121.     
  122.     c = data->d_char[1];
  123.     data->d_char[1] = data->d_char[2];
  124.     data->d_char[2] = c;
  125. }
  126.  
  127. /*
  128.  * longデータをLONG(big endian)データに変換
  129.  */
  130. LONG                /* big endianな long */
  131. long2LONG(
  132.     long n            /* 元のlong */
  133.     )
  134. {
  135.     any_t d;
  136.     
  137.     d.d_long = n;
  138.     conv_endian_long( &d);
  139.  
  140.     return ( d.d_LONG);
  141. }
  142.  
  143. /*
  144.  * shortデータをSHORT(big endian)データに変換
  145.  */
  146. SHORT            /* big endianな short */
  147. short2SHORT(
  148.     short n            /* 元のshort */
  149.     )
  150. {
  151.     any_t d;
  152.     
  153.     d.d_short = n;
  154.     conv_endian_short( &d);
  155.     
  156.     return ( d.d_SHORT);
  157. }
  158.  
  159. /*
  160.  * LONG( big endian)をlongに変換 
  161.  */
  162. long            /* 変換後のlong */
  163. LONG2long(
  164.     LONG n                /* big endian な long */
  165.     )
  166. {
  167.     any_t d;
  168.     
  169.     d.d_LONG = n;
  170.     conv_endian_long( &d);
  171.  
  172.     return ( d.d_long);
  173. }
  174.  
  175. /*
  176.  * SHORT( big endian)をshortに変換
  177.  */
  178. short            /* 変換後のshort */
  179. SHORT2short(
  180.     SHORT n                /* big endian な short */
  181.     )
  182. {
  183.     any_t d;
  184.     
  185.     d.d_SHORT = n;
  186.     conv_endian_short( &d);
  187.     
  188.     return ( d.d_short);
  189. }
  190.  
  191. #endif /* BIG_ENDIAN */
  192.  
  193. long read_file(P2* p2, void* mem, long size)
  194. {
  195.     OSErr result;
  196.     long readsize = size;
  197.     result = FSRead(p2->fds, &readsize, (Ptr)mem);
  198.     if (result != noErr)
  199.         p2errno = p2->errno = result;
  200.     else if (readsize < size)
  201.         p2errno = p2->errno = P2E_FEOF;
  202.     return readsize;
  203. }
  204.  
  205. /*
  206.  * ファイルから指定量のデータを読み込む、ただしEOFを超えても
  207.  * エラーがセットされないのが違うだけです。
  208.  */
  209. long read_file2(P2* p2, void* mem, long size)
  210. {
  211.     OSErr result;
  212.     long readsize = size;
  213.     result = FSRead(p2->fds, &readsize, (Ptr)mem);
  214.     if (result != noErr && result != eofErr)
  215.         p2errno = p2->errno = result;
  216.     return readsize;
  217. }
  218.  
  219. /*
  220.  * ファイルから1バイト読み込む
  221.  */
  222. uchar                        /* 読み込んだ値 */
  223. read_char(
  224.     P2 *p2                    /* ハンドル */
  225.     )
  226. {
  227.     uchar a;
  228.  
  229.     read_file( p2, &a, 1);
  230.     return( a);
  231. }
  232.  
  233. /*
  234.  * ファイルから shortデータを読み込む
  235.  */
  236. ushort                        /* 読み込んだ値 */
  237. read_short(
  238.     P2 *p2                    /* ハンドル */
  239.     )
  240. {
  241.     any_t data;
  242.  
  243.     read_file( p2, &data, 2);
  244.  
  245.     /* エンディアンの修正 */
  246.     conv_endian_short( &data);
  247.  
  248.     return ( data.d_short);
  249. }
  250.  
  251. #if 0
  252. /*
  253.  * ファイルから longデータを読み込む
  254.  */
  255. ulong                        /* 読み込んだ値 */
  256. read_long(
  257.     P2 *p2                    /* ハンドル */
  258.     )
  259. {
  260.     any_t data;
  261.  
  262.     read_file( p2, &data, 4);
  263.  
  264.     /* エンディアンの修正 */
  265.     conv_endian_long( &data);
  266.     return ( data.d_long);
  267. }
  268. #endif
  269.  
  270. /*
  271.  * ファイルに指定量のデータを書き込む
  272.  */
  273. long write_file(P2* p2, void* mem, long size)
  274. {
  275.     OSErr result;
  276.     long writesize = size;
  277.     result = FSWrite(p2->fds, &writesize, (Ptr)mem);
  278.     if (result != noErr)
  279.         p2errno = p2->errno = result;
  280.     else if (writesize != size)
  281.         p2->errno = p2errno = dskFulErr;
  282.     return writesize;
  283. }
  284. /*
  285.  * ファイルに1バイト書き込む
  286.  */
  287. long                        /* 書き込んだ量 (1のはず ) */
  288. write_char(
  289.     P2 *p2,                    /* ハンドル */
  290.     char a                    /* データ */
  291.     )
  292. {
  293.     return ( write_file( p2, &a, 1));
  294. }
  295.  
  296. /*
  297.  * ファイルに shortデータを書き込む
  298.  */
  299. long                        /* 書き込んだ量 ( 2のはず) */
  300. write_short(
  301.     P2 *p2,                    /* ハンドル */
  302.     short n                    /* データ */
  303.     )
  304. {
  305.     any_t data;
  306.     
  307.     data.d_short = n;
  308.  
  309.     /* エンディアン変換 */
  310.     conv_endian_short( &data);
  311.  
  312.     return ( write_file( p2, &data.d_SHORT, 2));
  313. }
  314.  
  315. /*
  316.  * ファイルにlongデータを書き込む
  317.  */
  318. long                        /* 書き込んだ量 ( 4のはず ) */
  319. write_long(
  320.     P2 *p2,                    /* ハンドル */
  321.     long n                    /* データ */
  322.     )
  323. {
  324.     any_t data;
  325.     
  326.     data.d_long = n;
  327.     /* エンディアン変換 */
  328.     conv_endian_long( &data);
  329.  
  330.     return ( write_file( p2, &data.d_LONG, 4));
  331. }
  332.  
  333.  
  334. /*
  335.  * ファイルをシークする
  336.  */
  337. long seek_file(P2* p2, long pos)
  338. {
  339.     OSErr result;
  340.     long    filesize;
  341.  
  342.     pos += p2->macbin_offset;
  343.  
  344.     // Change for Macintosh:
  345.     //  シークだけでファイルサイズを大きくできないので SetEOF を使う。
  346.     GetEOF(p2->fds, &filesize);
  347.     if(p2->mode == P2_OPEN_WRITE && pos>filesize)
  348.         SetEOF(p2->fds, pos);
  349.  
  350.     result = SetFPos(p2->fds, fsFromStart, pos);
  351.  
  352.     if (result != noErr)
  353.     {    p2errno = p2->errno = result;
  354.         return    -1;
  355.     }
  356.  
  357.     pos -= p2->macbin_offset;
  358.     return    pos;
  359. }
  360.  
  361. /*
  362.  * ファイルの現在の位置を得る
  363.  */
  364. long tell_file(P2* p2)
  365. {
  366.     OSErr result;
  367.     long n;
  368.     result = GetFPos(p2->fds, &n);
  369.  
  370.     if (result != noErr)
  371.     {    p2errno = p2->errno = result;
  372.         return    -1;
  373.     }
  374.     n -= p2->macbin_offset;
  375.  
  376.     return n;
  377. }
  378.  
  379.  
  380. /*
  381.  * セーブするデータ用にパレットを設定する。
  382.  * (なお、既にオープンされているP2ファイルには設定できない)
  383.  */
  384. void
  385. p2setpal( 
  386.     short n_pal,        /* パレット数 */
  387.     short n_bits,        /* パレット有効ビット長 */
  388.     uchar pal[][3]        /* パレットデータ */
  389.     )
  390. {
  391. //    assert( 0 < n_pal && n_pal <= 256);
  392. //    assert( 0 < n_bits && n_bits <= 256);
  393.     
  394.     /* パレット数を保存 */
  395.     n_palette = n_pal;
  396.  
  397.     /* パレット有効ビット長を保存 */
  398.     palette_bits = n_bits;
  399.  
  400.     memcpy( palette_data, pal, n_pal * 3);
  401. }
  402.  
  403. /*
  404.  * フレームバッファ/セーバ/作者名などの環境をセットする
  405.  */
  406. void
  407. p2setenv(
  408.     char *savername,    /* セーバ名                */
  409.     short ncolor,        /* 色数をビット数        */
  410.     long xmax,            /* 最大幅(−1で自動)    */
  411.     long ymax,            /* 最大高(−1で自動    */
  412.     short xasp,            /* 横比率                */
  413.     short yasp,            /* 縦比率                */
  414.     short rawbeta        /* ベタ展開形式(0=他と同じ/1=ベタのまま) */
  415.     )
  416. {
  417.     strncpy( (char *)saver,(char *)savername, 30);
  418.     saver[30] = '¥0';
  419.     depth = ncolor;
  420.     x_max = xmax;
  421.     y_max = ymax;
  422.     x_aspect = xasp;
  423.     y_aspect = yasp;
  424.     raw_beta = rawbeta;
  425. }
  426.  
  427. /*
  428.  * ヘッダを読み込む
  429.  */
  430. static void
  431. read_header( P2 *p2)
  432. {
  433. #if 0
  434. //#ifndef    PADDING_STRUCT
  435.     read_file( p2, &p2->header, sizeof( p2->header));
  436. #else
  437.     read_file( p2, p2->header.magic, 4);
  438.     read_file( p2, p2->header.name, 18);
  439.     read_file( p2, p2->header.subtitle, 8);
  440.     read_file( p2, p2->header.crlf0, 2);
  441.     read_file( p2, p2->header.title, 30);
  442.     read_file( p2, p2->header.crlf1, 2);
  443.     read_file( p2, p2->header.saver, 30);
  444.     read_file( p2, p2->header.crlf2, 2);
  445.     read_file( p2, &p2->header.eof, 1);
  446.     read_file( p2, &p2->header.reserve0, 1);
  447.     read_file( p2, &p2->header.flag, 2);
  448.     read_file( p2, &p2->header.no, 2);
  449.     read_file( p2, &p2->header.time, 4);
  450.     read_file( p2, &p2->header.size, 4);
  451.     read_file( p2, &p2->header.depth, 2);
  452.     read_file( p2, &p2->header.x_aspect, 2);
  453.     read_file( p2, &p2->header.y_aspect, 2);
  454.     read_file( p2, &p2->header.x_max, 2);
  455.     read_file( p2, &p2->header.y_max, 2);
  456.     read_file( p2, &p2->header.reserve1, 4);
  457. #endif
  458. }
  459.  
  460. /*
  461.  * ヘッダを書き込む
  462.  */
  463. static void
  464. write_header( P2 *p2)
  465. {
  466. #if 0
  467. //#ifndef    PADDING_STRUCT
  468.     write_file( p2, &p2->header, sizeof( p2->header));
  469. #else
  470.     write_file( p2, p2->header.magic, 4);
  471.     write_file( p2, p2->header.name, 18);
  472.     write_file( p2, p2->header.subtitle, 8);
  473.     write_file( p2, p2->header.crlf0, 2);
  474.     write_file( p2, p2->header.title, 30);
  475.     write_file( p2, p2->header.crlf1, 2);
  476.     write_file( p2, p2->header.saver, 30);
  477.     write_file( p2, p2->header.crlf2, 2);
  478.     write_file( p2, &p2->header.eof, 1);
  479.     write_file( p2, &p2->header.reserve0, 1);
  480.     write_file( p2, &p2->header.flag, 2);
  481.     write_file( p2, &p2->header.no, 2);
  482.     write_file( p2, &p2->header.time, 4);
  483.     write_file( p2, &p2->header.size, 4);
  484.     write_file( p2, &p2->header.depth, 2);
  485.     write_file( p2, &p2->header.x_aspect, 2);
  486.     write_file( p2, &p2->header.y_aspect, 2);
  487.     write_file( p2, &p2->header.x_max, 2);
  488.     write_file( p2, &p2->header.y_max, 2);
  489.     write_file( p2, &p2->header.reserve1, 4);
  490. #endif
  491. }
  492.  
  493. static void
  494. read_blk_header_from_flag( P2 *p2)
  495. {
  496. #if 0
  497. //#ifndef    PADDING_STRUCT
  498.     read_file( p2, (char *)&p2->blk + offsetof( struct  p2_blk, flag)
  499.         , sizeof( p2->blk) - offsetof( struct p2_blk, flag));
  500. #else
  501.     /* read_file( p2, p2->blk.id, 4); */
  502.     /* read_file( p2, &p2->blk.size, 4); */
  503.     read_file( p2, &p2->blk.flag, 2);
  504.     read_file( p2, &p2->blk.x_wid, 2);
  505.     read_file( p2, &p2->blk.y_wid, 2);
  506.     read_file( p2, &p2->blk.x_offset, 2);
  507.     read_file( p2, &p2->blk.y_offset, 2);
  508.     read_file( p2, &p2->blk.opaque, 4);
  509.     read_file( p2, &p2->blk.reserve, 4);
  510. #endif
  511. }
  512.  
  513. static void
  514. write_blk_header( P2 *p2)
  515. {
  516. #if 0
  517. //#ifndef    PADDING_STRUCT
  518.     write_file( p2, &p2->blk, sizeof( p2->blk));
  519. #else
  520.     write_file( p2, &p2->blk.id, 4);
  521.     write_file( p2, &p2->blk.size, 4);
  522.     write_file( p2, &p2->blk.flag, 2);
  523.     write_file( p2, &p2->blk.x_wid, 2);
  524.     write_file( p2, &p2->blk.y_wid, 2);
  525.     write_file( p2, &p2->blk.x_offset, 2);
  526.     write_file( p2, &p2->blk.y_offset, 2);
  527.     write_file( p2, &p2->blk.opaque, 4);
  528.     write_file( p2, &p2->blk.reserve, 4);
  529. #endif
  530. }
  531.  
  532. /*
  533.  * pic2ファイルを読み込みでオープンする。
  534.  */
  535.  
  536. P2* p2open(FSSpec* fname)
  537. {
  538.     P2 * p2;
  539.     short fds = 0;
  540.     OSErr result;
  541.     long comment_size;
  542.  
  543.     /* とりあえず ファイルをオープンする */
  544.     result = HOpen(fname->vRefNum, fname->parID, fname->name, fsCurPerm, &fds);
  545.  
  546.     if (result != noErr)
  547.     {
  548.         p2errno = result;
  549.         return NULL;
  550.     }
  551.  
  552.     /* 必要なメモリを確保してハンドルを作る。
  553.      * (なおメモリ確保関数内でのメモリクリアが暗示的な初期化になっている。)
  554.      */
  555.     p2 = mem_alloc( sizeof( *p2));
  556.     if ( p2 == NULL) goto err;
  557.  
  558.     p2->fds = fds;
  559.     p2->mode = P2_OPEN_READ;
  560.  
  561.     /* pic2のヘッダを読み込む */
  562.     read_header( p2);
  563.  
  564.     /* マックバイナリ簡易対応 */
  565.     if ( memcmp( p2->header.magic, "P2DT", 4) != 0) {
  566.         /* もしIDが無い時は、128バイト先にIDがあるか見てみる */
  567.         seek_file( p2, 128);
  568.         read_header( p2);
  569.         if ( memcmp( p2->header.magic, "P2DT", 4) != 0) {
  570.             p2errno = p2->errno = P2E_BADFORM;
  571.             goto err;
  572.         }
  573.         p2->macbin_offset = 128;
  574.     }
  575.  
  576.     /* パレットがある場合はパレットも読む */
  577.     if ( SHORT2short( p2->header.flag) & 1) {
  578.         p2->pal_bits = read_char( p2);
  579.         p2->n_pal = read_short( p2);
  580.         read_file( p2, p2->pal, p2->n_pal * 3);
  581.     }
  582.  
  583.     /* コメントの読み込み */
  584.     comment_size = LONG2long( p2->header.size) - tell_file( p2);
  585.     p2->comment = mem_alloc( comment_size + 1);
  586.     if ( p2->comment == NULL) goto err;
  587.     read_file( p2, p2->comment, comment_size);
  588.  
  589.     /* サイズ取得 */
  590.     p2->x_max = SHORT2short( p2->header.x_max);
  591.     p2->y_max = SHORT2short( p2->header.y_max);
  592.  
  593.     /* 始めのブロック位置セット */
  594.     p2->next_pos = tell_file( p2);
  595.  
  596.     /* エラーが無かった時はハンドルを戻す */
  597.     if ( p2->errno == 0) return ( p2);
  598.  
  599. err:; /* エラー時は、確保したメモリを解放して NULLを戻す */
  600.     if ( p2 != NULL) {
  601.         FREE( p2->comment);
  602.     }
  603.     FREE( p2);
  604.     FSClose(fds);
  605.  
  606.     return ( NULL);
  607. }
  608. /*
  609.  * pic2ファイルを作成モードでオープンする。
  610.  */
  611. P2 *                    /* 成功時はハンドル、エラー時は NULL */
  612. p2creat(
  613.     FSSpec *fname,        /* ファイル名    */
  614.     char *title,        /* タイトル        */
  615.     char *comment,        /* コメント        */
  616.     char *name,            /* 作者名        */
  617.     short no            /* 作品番号        */
  618.     )
  619. {
  620.     P2 *p2;
  621.     short fds;
  622.     OSErr result;
  623.     
  624.     /* ファイルを作成 */
  625.     HDelete(fname->vRefNum, fname->parID, fname->name);
  626.     result = HCreate(fname->vRefNum, fname->parID, fname->name, 'Q4ツd', 'PIC2');
  627.     if (result != noErr)
  628.     {
  629. erropen:;
  630.         p2errno = result;
  631.         return (NULL);
  632.     }
  633.  
  634.     result = HOpen(fname->vRefNum, fname->parID, fname->name, fsRdWrPerm, &fds);
  635.  
  636.     if (result != noErr)    goto erropen;
  637.  
  638.     /* ハンドラの確保と初期化
  639.      * (なおメモリ確保でのメモリクリアが暗示的な初期化になっている。)
  640.      */
  641.     p2 = mem_alloc( sizeof( *p2));
  642.     if ( p2 == NULL) goto err;
  643.     p2->fds = fds;
  644.     p2->mode = P2_OPEN_WRITE;
  645.     
  646.     /* ヘッダは最後に書き込むので取り敢えずシークしとく
  647.      * (無い所シークできない人は代わりにダミーで何か書いてね)
  648.      */
  649.     seek_file( p2, SIZE_OF_HEADER);
  650.  
  651.     /* パレットを書き込むぞ */
  652.     if ( n_palette > 0) {
  653.         write_char( p2, palette_bits);
  654.         write_short( p2, n_palette);
  655.         write_file( p2, palette_data, n_palette * 3);
  656.     }
  657.  
  658.     /* コメントのセーブ */
  659.  
  660.     /*
  661.      *  Mac/Unix/DOS(Human68k,MS-DOS)間の改行処理の違いをこの関数の中で
  662.      *  吸収してしまうように変更しました。( by N.Abe 1994/02/15 )
  663.      *
  664.      */
  665.  
  666. #define  COM_CR     0x0d
  667. #define  COM_LF     0x0a
  668. #define  COM_TERM   0x00
  669.  
  670.     if ( comment != NULL ) {
  671.          register char *q = comment;
  672.          uchar c;
  673.  
  674.          while( (c=*q++) != '¥0' )  {
  675.             switch( c )  {
  676.                case  '¥0'  :
  677.                   break;
  678.                case  COM_CR:
  679.                   if ( *q == COM_LF )  {
  680.                        break;
  681.                   }
  682.                case  COM_LF:
  683.                   write_char( p2, COM_CR );
  684.                   write_char( p2, COM_LF );
  685.                   break;
  686.                default     :
  687.                   write_char( p2, c );
  688.                   break;
  689.             }
  690.          }
  691.     }
  692.  
  693.     write_char( p2, COM_TERM );
  694.  
  695. #undef  COM_CR
  696. #undef  COM_LF
  697. #undef  COM_TERM
  698.  
  699.     /* 次にセーブするブロック位置をせっと */
  700.     p2->next_pos = tell_file( p2);
  701.  
  702.     /* ヘッダに情報セット */
  703.     p2->header.size = long2LONG( p2->next_pos);
  704.     memcpy( p2->header.magic, "P2DT", 4);
  705.     strcpy2( p2->header.name, (uchar *)name, 18);
  706.  
  707.     /* サブタイトルをファイル名から作る */
  708.     {
  709.         char *p,*pp;
  710.         Str255    str;
  711.         
  712.         BlockMove(fname->name,str,63);
  713.  
  714.         p = (char*)(&str[1]);
  715.         /* ドライブとパスと拡張子を取り除く (漢字ファイル名だととちる事がある) */
  716. #if 0
  717.         if ( (pp = strrchr( p, ':')) != NULL) p = pp + 1;
  718.         if ( (pp = strrchr( p, '/')) != NULL) p = pp + 1;
  719.         if ( (pp = strrchr( p, '¥¥')) != NULL) p = pp + 1;
  720. #endif
  721.         pp = strchr( p, '.');
  722.         /* 元の文字列を一時的に書き換えるので余りよろしくない ^^; */
  723.         if ( pp != NULL) *pp = '¥0';
  724.         strcpy2( p2->header.subtitle, (uchar *)p, 8); 
  725.     }
  726.  
  727.     p2->header.crlf0[0] = p2->header.crlf1[0] = p2->header.crlf2[0] = 0x0d;
  728.     p2->header.crlf0[1] = p2->header.crlf1[1] = p2->header.crlf2[1] = 0x0a;
  729.  
  730.     strcpy2( p2->header.title, (uchar *)title, 30);
  731.     strcpy2( p2->header.saver, saver, 30);
  732.     p2->header.eof = 0x1a;
  733.     p2->header.reserve0 = p2->header.reserve1 = 0;
  734.  
  735.     if ( n_palette > 0) {
  736.         p2->header.flag = short2SHORT( 1);
  737.     } else {
  738.         p2->header.flag = short2SHORT( 0);
  739.     }
  740.     p2->header.no = short2SHORT( no);
  741.     p2->header.depth = short2SHORT( depth);
  742.     p2->header.x_aspect = short2SHORT( x_aspect);
  743.     p2->header.y_aspect = short2SHORT( y_aspect);
  744.     p2->header.x_max = short2SHORT( x_max);
  745.     p2->header.y_max = short2SHORT( y_max);
  746.  
  747.     /* ハンドラに情報をセット */
  748.     p2->n_pal = n_palette;
  749.     p2->pal_bits = palette_bits;
  750.     memcpy( p2->pal, palette_data, n_palette * 3);
  751.     
  752.     p2->n_pal = n_palette;
  753.     p2->pal_bits = palette_bits;
  754.     memcpy( p2->pal, palette_data, n_palette * 3); /* パレットはコピーで取っておく
  755.                                        * ( 必要無い気もするけど ^^;) */
  756.     /* エラーが無かったらハンドルを戻す */
  757.     if ( p2->errno == 0) return ( p2);
  758.  
  759. err: /* エラー時は確保したメモリの解放などをする */
  760.     FREE( p2);
  761.     
  762.     return ( NULL);
  763. }
  764.  
  765.  
  766. /*
  767.  *    pic2 ファイルを追加モードでオープンする。
  768.  */
  769. P2 *                        /* 成功時はハンドル、エラー時は NULL */
  770. p2apend(
  771.     FSSpec *fname,            /* ファイル名        */
  772.     char *title,            /* タイトル            */
  773.     char *comment,            /* コメント            */
  774.     char *name,                /* 作者名            */
  775.     short no                /* 作品番号            */
  776.     )
  777. {
  778.     P2 *p2;
  779.     short n;
  780.     short fds;    OSErr result;
  781.  
  782.     /* 取り敢えずリードでオープン */
  783.     p2 = p2open( fname);
  784.     if ( p2 == NULL) {
  785.         /* 新規作成でオープンし直す */
  786.         return ( p2creat( fname, title, comment, name, no));
  787.     }
  788.  
  789.     if ( SHORT2short( p2->header.depth) != depth) {
  790.         p2close( p2);
  791.         p2errno = P2E_BADFORM;
  792.         return ( NULL);
  793.     }
  794.  
  795.     /* 追加なので最後のブロック次まで移動する */
  796.     n = p2find( p2);        /* はじめのブロックを探して */
  797.     while ( n > 0) {
  798.         n = p2next( p2);    /* なくなるまで探しつづける */
  799.     }
  800.     if ( n != 0) {            /* エラ-だったら終わり */
  801.         p2close( p2);
  802.         return ( NULL);
  803.     }
  804.  
  805.     /* ファイルを書き込み用に開きなおす */
  806.     result = HOpen(fname->vRefNum, fname->parID, fname->name, fsCurPerm, &fds);
  807.     if (result != noErr)
  808.     {
  809.         p2close(p2);
  810.         return NULL;
  811.     }
  812.     FSClose( p2->fds);
  813.  
  814.     /* 新しい情報を有効にする、ただしコメント変更は
  815.      * かなり面倒なので古い方のままである。
  816.      * また、このためタイトルも同じままにして有る。
  817.      */
  818.     strcpy2( p2->header.name, (uchar *)name, 18);
  819.     strcpy2( p2->header.saver, saver, 30);
  820.     p2->header.no = short2SHORT( no);
  821.     p2->header.x_aspect = short2SHORT( x_aspect);
  822.     p2->header.y_aspect = short2SHORT( y_aspect);
  823.     p2->header.x_max = short2SHORT( x_max);
  824.     p2->header.y_max = short2SHORT( y_max);
  825.  
  826.     p2->mode = P2_OPEN_WRITE;
  827.     p2->fds = fds;
  828.     return ( p2);
  829. }
  830.  
  831. /*
  832.  * 圧縮/展開ようのメモリを必要なら開放する。
  833.  */
  834. static void
  835. p2buffree(
  836.     P2 *p2                /* ハンドル */
  837.     )
  838. {
  839.     if ( p2->buff != NULL) return;
  840.     FREE( p2->vram_prev);
  841.     FREE( p2->vram_now);
  842.     FREE( p2->vram_next);
  843.     FREE( p2->flag_now);
  844.     FREE( p2->flag_next);
  845.     FREE( p2->flag2_now);
  846.     FREE( p2->flag2_next);
  847.     FREE( p2->flag2_next2);
  848.  
  849. #if defined(_DOS_)
  850.     if ( p2->cache ) HFREE( p2->cache );
  851. #else
  852.     FREE( p2->cache);
  853. #endif
  854.  
  855.     FREE( p2->cache_pos);
  856.     FREE( p2->mulu_tab);
  857. }
  858.  
  859. /*
  860.  * P2をクローズする
  861.  */
  862. short                /* 0=OK/-1=error */
  863. p2close(
  864.     P2 *p2            /* p2ハンドル */
  865.     )
  866. {
  867.     short err; OSErr result;
  868.  
  869.     /* 書き込みモードの場合 */
  870.     if ( p2->mode == P2_OPEN_WRITE) {
  871.         /* ブロックの終わりを書き込む */
  872.         seek_file( p2, p2->next_pos);
  873.         write_long( p2, 0);    /* ブロック終わりのID */
  874.         write_long( p2, 0);    /* オマケでサイズ0を入れる */
  875.  
  876.         /* ブロックの最大サイズが未セットの場合はセットする。 */
  877.         if ( SHORT2short( p2->header.x_max) < 0) {
  878.             p2->header.x_max = short2SHORT( p2->x_max);
  879.         }
  880.         if ( SHORT2short( p2->header.y_max) < 0) {
  881.             p2->header.y_max = short2SHORT( p2->y_max);
  882.         }
  883.  
  884.         /* 作成時刻をセット */
  885.         // convert from unix time()...1970/1/1
  886.         // MacOS GetDateTime Returns  1904/1/1 UNIX+0x7c262f10 = MacOS
  887.         {
  888.             // OSUtils.h
  889.             unsigned long tim;
  890.             GetDateTime(&tim);
  891.             p2->header.time = tim - 0x7c262f10L; // time( NULL));
  892.         }
  893.  
  894.         /* ヘッダの書き込み */
  895.         seek_file( p2, 0);
  896.         
  897.         write_header( p2);
  898.     }
  899.  
  900.     /* ファイルを閉じる */
  901.     if ( (result = FSClose( p2->fds)) < 0) p2->errno = result;
  902.  
  903.     /* メモリの開放 */
  904.     p2buffree( p2);
  905.     FREE( p2->comment);
  906.  
  907.     err = p2->errno;
  908.     FREE( p2);
  909.     
  910.     /* エラーならエラーリターン */
  911.     if ( err != 0) {
  912.         return ( -1);
  913.     }
  914.     return ( 0);
  915. }
  916.  
  917. /*
  918.  * 次のブロックを探す
  919.  */
  920. short                    /* 1=みっけ/0=おわり/2=見つけたけど未知のブロックだ/else=エラー */
  921. p2next(
  922.     P2 *p2            /* p2 ハンドル */
  923.     )
  924. {
  925.     long i;
  926.     long    (*ld_init)(P2*);
  927.     long    (*sv_init)(P2*,pix**);
  928.  
  929.     /* 書き込みモードは有効な処理ではないのでエラーで抜ける */
  930.     if ( p2->mode != P2_OPEN_READ ) return ( -1);
  931.  
  932.     /* これから読むブロックに移動 */
  933.     seek_file( p2, p2->next_pos);
  934.  
  935.     /* 取り敢えず頭の所だけ読み込む */
  936.     read_file( p2, &p2->blk, 8);
  937.     if ( p2->errno != 0) return ( -1);
  938.  
  939.     /* ブロックの終わりだったら、終わりでリターン */
  940.     if ( p2->blk.id[0] == 0) return ( 0);
  941.  
  942.     /* 今のブロック位置セット */
  943.     p2->blk_pos = p2->next_pos;
  944.  
  945.     /* 次のブロック位置セット */
  946.     p2->next_pos += LONG2long( p2->blk.size);
  947.  
  948.     /* 知っているブロックかな */
  949.     if(GetBlockTag(mem2long(p2->blk.id), &ld_init, &sv_init)==2)
  950.         return    2;    /* 知らないフォーマットだよん */
  951.  
  952.     /* ブロックヘッダの続き(flagから)よみこむ */
  953.     read_blk_header_from_flag( p2);
  954.  
  955.     /* p2->x_maxの全ブロック最大幅をチェックして必要なら更新 */
  956.     if ( SHORT2short( p2->blk.x_offset) + SHORT2short( p2->blk.x_wid) > p2->x_max) {
  957.         p2->x_max = SHORT2short( p2->blk.x_offset) + SHORT2short( p2->blk.x_wid);
  958.     }
  959.  
  960.     /* p2->y_maxの全ブロック最大高をチェックして必要なら更新 */
  961.     if ( SHORT2short( p2->blk.y_offset) + SHORT2short( p2->blk.y_wid) > p2->y_max) {
  962.         p2->y_max = SHORT2short( p2->blk.y_offset) + SHORT2short( p2->blk.y_wid);
  963.     }
  964.  
  965.     /* エラーなら、エラーリターン */
  966.     if ( p2->errno != 0) return ( -1);
  967.     return ( 1);
  968. }
  969.  
  970. /*
  971.  * 始めブロックを探す
  972.  */
  973. short                /* 1=みっけ/0=おわり/2=見つけたけど未知のブロックだ/else=エラー */
  974. p2find(
  975.     P2 *p2            /* ハンドル */
  976.     )
  977. {
  978.     /* 読み込みモードでなければエラーで終わり */
  979.     if ( p2->mode != P2_OPEN_READ ) return ( -1);
  980.  
  981.     /* はじめの位置をセットして p2nextを呼ぶ */
  982.     p2->next_pos = LONG2long( p2->header.size);
  983.     return ( p2next( p2));
  984. }
  985.  
  986. /*
  987.  * p2用の各種メモリを確保する
  988.  */
  989. static short                /* 0=OK / -1 = エラー */
  990. p2bufalloc(
  991.     P2 *p2                /* ハンドル */
  992.     )
  993. {
  994.     short wid;
  995.     
  996.     wid = SHORT2short( p2->blk.x_wid);
  997.  
  998.     p2errno = 0;
  999.     p2->vram_prev   = mem_alloc((wid + 8) * sizeof( pix));
  1000.     p2->vram_now    = mem_alloc((wid + 8) * sizeof( pix));
  1001.     p2->vram_next   = mem_alloc((wid + 8) * sizeof (pix));
  1002.     p2->flag_now    = mem_alloc( wid + 8);
  1003.     p2->flag_next   = mem_alloc( wid + 8);
  1004.     p2->flag2_now   = mem_alloc( wid + 8);
  1005.     p2->flag2_next  = mem_alloc( wid + 8);
  1006.     p2->flag2_next2 = mem_alloc( wid + 8);
  1007.  
  1008. #if defined(_DOS_)
  1009.     p2->cache = (pix (_HUGE_ *)[N_COLOR_CACHE+1])HALLOC( 8*8*8,sizeof( *p2->cache) );
  1010.     if ( p2->cache == NULL )  {
  1011.          p2errno   = errno;
  1012.          p2->cache = NULL;
  1013.     }
  1014. #else
  1015.     p2->cache = mem_alloc( ((long)sizeof( *p2->cache) * 8 * 8 * 8) );
  1016. #endif
  1017.     p2->cache_pos = mem_alloc( sizeof( *p2->cache_pos) * 8 * 8 * 8);
  1018.     p2->mulu_tab = mem_alloc( sizeof( *p2->mulu_tab) * 16384);
  1019.     if ( p2errno != 0) {
  1020.         p2buffree( p2);
  1021.         return ( -1);
  1022.     }
  1023.     return ( 0);
  1024. }
  1025.  
  1026. /*
  1027.  * ブロックデータを展開する
  1028.  *
  1029.  *    始めにp2find/p2nextでブロックを探しておいて
  1030.  *    展開したいブロックの所で p2loadで展開を開始する。
  1031.  *    ひとつのp2ハンドラでは同時には展開/圧縮できないので注意、
  1032.  *  同じファイルで2つハンドルをオープンすれば
  1033.  *    同じファイルの違うブロックを同時に展開出来る。
  1034.  */
  1035. short                            /* 0= OK / -1 エラー */
  1036. p2load(
  1037.     P2 *p2                        /* ハンドル */
  1038.     )
  1039. {
  1040.     long    (*ld_init)(P2*);
  1041.     long    (*sv_init)(P2*,pix**);
  1042.  
  1043.     if(GetBlockTag(mem2long(p2->blk.id), &ld_init, &sv_init)==2)
  1044.     {
  1045.         /* 未知のIDはエラーでリターン */
  1046.         p2errno = p2->errno = P2E_BADFORM;
  1047.         return ( -1);
  1048.     }
  1049.     /* 展開用のバッファを確保して */
  1050.     p2bufalloc( p2);
  1051.  
  1052.     /* 該当 IDの初期化ルーチンに後はまかす */
  1053.     return ( *ld_init)( p2);
  1054. }
  1055.  
  1056. /*
  1057.  * ブロックデータにセーブをする
  1058.  *
  1059.  * セーブを開始する。そして戻り値で指定された(今は0ね)
  1060.  * ライン番号の情報を *line へセットして次に p2nline を呼び出します。
  1061.  * そして同様にライン番号と行バッファのポインタが戻るので
  1062.  * 再びデータをセットして p2nlineを呼ぶことを繰り返す。
  1063.  * なお、p2nlineの戻り値が-2で終わりです。(-1はエラー)
  1064.  * なお、0から最終ラインまで今の所連続してセットするように
  1065.  * なっているので戻り値のライン番号情報を律義に考えなくても
  1066.  * 特に問題はありません。
  1067.  * ただし2パス圧縮の時は一回最終ラインまで行った後に再び0から
  1068.  *  最終ラインを要求するので、この対応はしないといけません。
  1069.  *
  1070.  * ちなみに、始点がライン10でも0から要求されます。
  1071.  * つまり座標値ではなくて始点からの番号です。
  1072.  */
  1073. long                            /* -1=エラー / else = 欲しいデータのライン番号 (0のはず)*/
  1074. p2save(
  1075.     P2 *p2,                    /* ハンドル            */
  1076.     pix **line,                /* データをセットして欲しいラインバッファが戻る    */
  1077.     long x,                    /* 始点 -1 でなし    */
  1078.     long y,                    /* 始点 -1 でなし    */
  1079.     long xw,                    /* 幅                 */
  1080.     long yw,                    /* 高さ                */
  1081.     char *id,                /* ブロックID        */
  1082.     pix opaque                /* 透明色 0xffffffffだとなし */
  1083.     )
  1084. {
  1085.     long    (*ld_init)(P2*);
  1086.     long    (*sv_init)(P2*,pix**);
  1087.  
  1088.     if(GetBlockTag(mem2long(id), &ld_init, &sv_init)==2)
  1089.     {
  1090.         /* 既知のIDではなければエラーでリターン */
  1091.         p2errno = P2E_BADFORM;
  1092.         return -1;
  1093.     }
  1094.  
  1095.     memcpy( p2->blk.id, id, 4);
  1096.     p2->blk.x_wid = short2SHORT( xw);
  1097.     p2->blk.y_wid = short2SHORT( yw);
  1098.     p2->blk.x_offset = short2SHORT( x);
  1099.     p2->blk.y_offset = short2SHORT( y);
  1100.     p2->blk.reserve = short2SHORT( 0);
  1101.  
  1102.     /* 最大幅情報を更新 */
  1103.     if ( x < 0) x = 0;
  1104.     if ( y < 0) y = 0;
  1105.     if ( x + xw > p2->x_max) p2->x_max = x + xw;
  1106.     if ( y + yw > p2->y_max) p2->y_max = y + yw;
  1107.  
  1108.     /* 透明色をセット */
  1109.     if ( opaque != 0xffffffff) {
  1110.         p2->blk.flag = short2SHORT( 1);
  1111.         p2->blk.opaque = long2LONG( opaque);
  1112.     } else {
  1113.         p2->blk.flag = short2SHORT( 0);
  1114.         p2->blk.opaque = long2LONG( 0);
  1115.     }
  1116.     /* 圧縮に必要なバッファを確保 */
  1117.     p2bufalloc( p2);
  1118.  
  1119.     /* ブロックIDに応じた初期化ルーチンに後は任せる */
  1120.     return    (*sv_init)(p2, line);
  1121. }
  1122.  
  1123.  
  1124. /*
  1125.  * ブロックデータに次のラインをセーブ/ロードをする
  1126.  *
  1127.  * セーブ時
  1128.  * セーブ時はp2saveでもらったラインのデータをセットして呼び出します。
  1129.  * そしてライン番号と行バッファのポインタが戻るので再びデータをセットして
  1130.  * p2nlineを呼ぶことを繰り返します。
  1131.  * なお、おわり(-2)の時に特別な処理は必要有りません。
  1132.  * また終わったら再びp2saveで次のブロックをセーブすることが出来ます。
  1133.  *
  1134.  * ロード時
  1135.  * 次のラインを展開します。
  1136.  * ライン番号とラインバッファのポインタが戻るので、このラインに
  1137.  * ラインバッファの内容を転送すればOKです。
  1138.  */
  1139. long                        /* -2=おわり/-1=エラー/else=欲しいデータのライン番号 */
  1140. p2nline(
  1141.     P2 *p2,                /* ハンドル */
  1142.     pix **line            /* データをセットするラインバッファが戻る    */
  1143.     )
  1144. {
  1145.     long res = p2->nextline( p2, line);
  1146.  
  1147.     if ( res == -1) { /* error */
  1148.         p2buffree( p2);
  1149.     } else if ( res == -2) {
  1150.         if (  p2->mode == P2_OPEN_WRITE) { /* save ok end */
  1151.             long new_pos = tell_file( p2);
  1152.             
  1153.             seek_file( p2, p2->next_pos);
  1154.             p2->blk.size = long2LONG( new_pos - p2->next_pos);
  1155.             write_blk_header( p2);
  1156.             p2->next_pos = new_pos;
  1157.         }
  1158.         p2buffree( p2);
  1159.     }
  1160.     return ( res);
  1161. }
  1162.  
  1163. #if 0
  1164. /*
  1165.  * エラーの表示
  1166.  */
  1167. void
  1168. p2error( char *s)
  1169. {
  1170.     Str255    s1;
  1171.     strncpy((char*)(&s1[1]),s,254);
  1172.     s1[250]=0;
  1173.     s1[0] = strlen((char*)(&s1[1]));
  1174.     DebugStr(s1);
  1175. }
  1176. #endif
  1177.  
  1178. /* eof */